package com.catazy.jetpackstudy.act2.chapter2.aidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

import java.util.Collections;
import java.util.List;

/**
 * - 作者: Tao
 * - 日期: 2025/1/15
 * - 时间: 13:47
 * - 描述: IBookManagerOpera接口扩展了IInterface，定义了远程服务通信的接口
 */
public interface IBookManagerOpera extends IInterface {

    // 描述符，用于标识接口
    static final String DESCRIPTOR = "com.catazy.jetpackstudy.chapter2.aidl.IBookManager";

    // 定义交易代码，用于标识不同的远程操作
    static final int TRANSACTION_getBookList = (IBinder.FIRST_CALL_TRANSACTION);
    static final int TRANSACTION_addBook = (IBinder.FIRST_CALL_TRANSACTION + 1);

    /**
     * 获取书籍列表
     *
     * @return 书籍列表
     * @throws RemoteException 如果远程调用失败
     */
    public List<Book> getBookList() throws RemoteException;

    /**
     * 添加一本书籍
     *
     * @param book 要添加的书籍对象
     * @throws RemoteException 如果远程调用失败
     */
    public void addBook(Book book) throws RemoteException;

    /**
     * 实现IBookManagerOpera接口的代理类，用于远程通信
     */
    public class BookManagerImpl extends Binder implements IBookManagerOpera {

        public BookManagerImpl() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * 将IBinder对象转换为IBookManagerOpera接口
         * 此方法用于将Binder对象转换为IBookManagerOpera接口实现，以便进行跨进程通信
         *
         * @param obj IBinder对象，代表远程服务的Binder
         * @return 返回IBookManagerOpera接口的实现，如果无法转换，则返回null
         */
        public static IBookManagerOpera asInterface(IBinder obj) {
            // 如果传入的IBinder对象为null，则直接返回null
            if ((obj == null)) {
                return null;
            }
            // 尝试从IBinder对象中获取本地接口
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            // 如果获取到的本地接口实例是IBookManagerOpera类型，则直接返回
            if (((iin instanceof IBookManagerOpera))) {
                return ((IBookManagerOpera) iin);
            }
            // 如果不是，则创建并返回一个BookManagerImpl.Proxy实例，用于与远程服务进行通信
            return new BookManagerImpl.Proxy(obj);
        }

        @Override
        public IBinder asBinder() {
            return this;
        }

        /**
         * 处理交易请求的方法，用于跨进程通信
         *
         * @param code 交易代码，标识不同的交易类型
         * @param data 包含交易数据的Parcel对象
         * @param reply 用于回复交易结果的Parcel对象
         * @param flags 交易的附加标志
         * @return true表示交易成功处理，false表示交易失败或未被处理
         * @throws RemoteException 当远程通信发生错误时抛出此异常
         */
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            // 获取接口描述符
            String descriptor = DESCRIPTOR;

            // 根据交易代码执行相应的操作
            switch (code) {
                // 当交易代码为INTERFACE_TRANSACTION时，回复接口描述符
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                // 当交易代码为TRANSACTION_getBookList时，执行获取书籍列表的操作
                case TRANSACTION_getBookList: {
                    data.enforceInterface(descriptor);
                    List<Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                // 当交易代码为TRANSACTION_addBook时，执行添加书籍的操作
                case TRANSACTION_addBook: {
                    data.enforceInterface(descriptor);
                    Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
                // 当交易代码不匹配上述任何情况时，调用父类方法处理
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }


        private static class Proxy implements IBookManagerOpera {
            public static IBookManagerOpera sDefaultImpl;

            private IBinder mRemote;

            Proxy(IBinder remote) {
                mRemote = remote;
            }

            @Override
            public IBinder asBinder() {
                return mRemote;
            }

            public String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * 重写getBookList方法，用于获取书籍列表<br>
             *
             * 此方法通过跨进程通信（IPC）机制，从远程服务获取书籍列表<br>
             * 它首先创建两个Parcel对象，用于发送请求和接收响应<br>
             * 尝试写入接口令牌以标识接口，然后通过mRemote对象进行跨进程通信<br>
             * 如果通信失败，尝试使用默认实现获取书籍列表<br>
             * 读取响应数据，将接收到的书籍列表数据转换为List<Book>类型并返回
             *
             * @return List<Book> 返回书籍列表
             * @throws RemoteException 如果跨进程通信失败，则抛出此异常
             */
            @Override
            public List<Book> getBookList() throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                List<Book> _result;
                try {
                    // 写入接口令牌，用于验证接口的正确性
                    _data.writeInterfaceToken(DESCRIPTOR);
                    // 通过TRANSACTION_getBookList标识发起跨进程通信
                    boolean _status = mRemote.transact(BookManagerImpl.TRANSACTION_getBookList, _data, _reply, 0);
                    // 如果通信失败且存在默认实现，则使用默认实现获取书籍列表
                    if (!_status && getDefaultImpl() != null) {
                        return getDefaultImpl().getBookList();
                    }
                    // 读取响应中的异常信息
                    _reply.readException();
                    // 从响应中读取书籍列表
                    _result = _reply.createTypedArrayList(Book.CREATOR);
                } finally {
                    // 回收Parcel对象以释放资源
                    _reply.recycle();
                    _data.recycle();
                }
                // 返回书籍列表
                return _result;
            }


            /**
             * 重写addBook方法，用于添加书籍
             *
             * @param book 要添加的书籍对象
             * @throws RemoteException 如果跨进程通信失败，则抛出此异常
             */
            @Override
            public void addBook(Book book) throws RemoteException {
                // 创建Parcel对象以用于数据传输
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                try {
                    // 写入接口令牌以确保通信双方使用相同的接口
                    _data.writeInterfaceToken(DESCRIPTOR);
                    // 判断book对象是否为null，如果不为null，则写入book的数据
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        // 如果book为null，则写入0表示null
                        _data.writeInt(0);
                    }
                    // 通过transact方法与远程服务通信，发送添加书籍的请求
                    boolean _status = mRemote.transact(BookManagerImpl.TRANSACTION_addBook, _data, _reply, 0);
                    // 如果transact返回false且存在默认实现，则调用默认实现的addBook方法
                    if (!_status && getDefaultImpl() != null) {
                        getDefaultImpl().addBook(book);
                        return;
                    }
                    // 读取回复中的异常信息，如果有的话
                    _reply.readException();
                } finally {
                    // 回收Parcel对象以释放资源
                    _reply.recycle();
                    _data.recycle();
                }
            }

        }

        public static IBookManagerOpera getDefaultImpl() {
            return BookManagerImpl.Proxy.sDefaultImpl;
        }

        public static boolean setDefaultImpl(IBookManagerOpera impl) {
            if (BookManagerImpl.Proxy.sDefaultImpl == null && impl != null) {
                BookManagerImpl.Proxy.sDefaultImpl = impl;
                return true;
            }
            return false;
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            return Collections.emptyList();
        }

        @Override
        public void addBook(Book book) throws RemoteException {

        }

        /**
         * 死亡代理
         */
        private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
            }
        };
    }
}

